package com.knife.cachev2.infra.init;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.knife.redis.KnifeRedisHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author lth
 * @created 2025年07月29日 星期二 8:36
 */
@SuppressWarnings("ALL")
@Slf4j
public class GroupRedisCacheTemplate<T> implements RedisCacheInitiator {

    /**
     * 缓存的键前缀
     */
    private String prefix;
    /**
     * 缓存数据
     */
    private Supplier<List<T>> cacheDataSupplier;

    /**
     * map缓存的键
     */
    private Function<T, String> mapKeySupplier;

    /**
     * 属性缓存的键
     */
    private Function<T, String> keySupplier;

    /**
     * 缓存放入的数据库
     */
    private int db;

    /**
     * redis操作
     */
    private KnifeRedisHelper knifeRedisHelper;

    /**
     * mapper序列化
     */
    private ObjectMapper objectMapper;

    public GroupRedisCacheTemplate(int db,
                                   String prefix,
                                   Supplier<List<T>> cacheDataSupplier,
                                   Function<T, String> mapKeySupplier,
                                   Function<T, String> keySupplier,
                                   KnifeRedisHelper knifeRedisHelper,
                                   ObjectMapper objectMapper) {
        this.cacheDataSupplier = cacheDataSupplier;
        this.mapKeySupplier = mapKeySupplier;
        this.keySupplier = keySupplier;
        this.db = db;
        this.prefix = prefix;
        this.knifeRedisHelper = knifeRedisHelper;
        this.objectMapper = objectMapper;
    }


    /**
     * 读取缓存
     *
     * @param param 参数
     * @return 缓存
     */
    public T getCache(T param) {
        String mapKey = mapKeySupplier.apply(param);
        String key = keySupplier.apply(param);
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(mapKey)) {
            log.warn("未找到缓存键值");
            return null;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            String str = knifeRedisHelper.hshGet(prefix + ":" + mapKey, key);
            return objectMapper.readValue(str, (Class<T>) param.getClass());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 读取缓存
     *
     * @param param 参数
     * @return 缓存
     */
    public List<T> getGroupCache(T param) {
        String mapKey = mapKeySupplier.apply(param);
        if (StringUtils.isEmpty(mapKey)) {
            log.warn("未找到缓存键值");
            return null;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            Map<String, String> map = knifeRedisHelper.hshGetAll(prefix + ":" + mapKey);
            List<T> list = new ArrayList<>(map.size());
            for (String str : map.values()) {
                list.add(objectMapper.readValue(str, (Class<T>) param.getClass()));
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 设置缓存
     *
     * @param cacheObj 缓存对象
     */
    public void setCache(T cacheObj) {
        String mapKey = mapKeySupplier.apply(cacheObj);
        String key = keySupplier.apply(cacheObj);
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(mapKey)) {
            log.warn("未找到缓存键值");
            return;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            knifeRedisHelper.hshPut(prefix + ":" + mapKey, key, objectMapper.writeValueAsString(cacheObj));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }

    /**
     * 缓存集合
     *
     * @param list 待缓存数据
     * @throws JsonProcessingException 异常
     */
    private void cacheList(List<T> list) {
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            for (T t : list) {
                String mapKey = mapKeySupplier.apply(t);
                String key = keySupplier.apply(t);
                if (StringUtils.isEmpty(key) || StringUtils.isEmpty(mapKey)) {
                    log.warn("未找到缓存键值");
                    continue;
                }
                knifeRedisHelper.hshPut(prefix + ":" + mapKey, key, objectMapper.writeValueAsString(t));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }


    /**
     * 删除缓存
     *
     * @param cacheObj 包含key
     */
    public void deleteCache(T cacheObj){
        String mapKey = mapKeySupplier.apply(cacheObj);
        String key = keySupplier.apply(cacheObj);
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(mapKey)) {
            log.warn("未找到缓存键值");
            return;
        }
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            knifeRedisHelper.hshDelete(prefix + ":" + mapKey,key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }


    @Override
    public void init() {
        List<T> list = cacheDataSupplier.get();
        cacheList(list);
    }

    @Override
    public void clear() {
        knifeRedisHelper.setCurrentDatabase(this.db);
        try {
            Set<String> keys = knifeRedisHelper.getRedisTemplate().keys(prefix+"*");
            if (Objects.nonNull(keys)) {
                knifeRedisHelper.getRedisTemplate().delete(keys);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            knifeRedisHelper.clearCurrentDatabase();
        }
    }
}
